package com.summer.web.v1.base.db;

import com.summer.common.lib.core.function.ThrowableFunction;

import java.lang.reflect.Method;
import java.sql.*;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Consumer;

import static org.apache.commons.lang.ClassUtils.wrapperToPrimitive;

/**
 * Derby
 */
@Deprecated
public class DerbyDBManager {

    private static DerbyDBManager dbManager = new DerbyDBManager();

    private Connection connection;

    private DerbyDBManager() {
        try {
            this.connection = DBUtil.getDataSource().getConnection();
        } catch (SQLException throwables) {
            throwables.printStackTrace();
        }
    }

    public static DerbyDBManager getInstance() {
        return dbManager;
    }

    public Connection getConnection() {
        return connection;
    }

    /**
     * 数据类型与 ResultSet 方法名映射
     */
    private static Map<Class, String> resultSetMethodMappings = new HashMap<>();

    private static Map<Class, String> preparedStatementMethodMappings = new HashMap<>();

    static {
        resultSetMethodMappings.put(Long.class, "getLong");
        resultSetMethodMappings.put(String.class, "getString");

        preparedStatementMethodMappings.put(Long.class, "setLong");
        preparedStatementMethodMappings.put(String.class, "setString");
    }


    public <T> T executeQuery(String sql, ThrowableFunction<ResultSet, T> function, Consumer<Throwable> exceptionHandler, Object... args) {
        Connection connection = getConnection();
        try {
            PreparedStatement preparedStatement = connection.prepareStatement(sql);
            for (int i = 0; i < args.length; i++) {
                Object arg = args[i];
                Class argType = arg.getClass();

                Class wrapperType = wrapperToPrimitive(argType);

                if (wrapperType == null) {
                    wrapperType = argType;
                }

                // Boolean -> boolean
                String methodName = preparedStatementMethodMappings.get(argType);
                Method method = PreparedStatement.class.getMethod(methodName, wrapperType);
                method.invoke(preparedStatement, i + 1, args);
            }
            ResultSet resultSet = preparedStatement.executeQuery();
            // 返回一个 POJO List -> ResultSet -> POJO List
            // ResultSet -> T
            return function.apply(resultSet);
        } catch (Throwable e) {
            exceptionHandler.accept(e);
        }
        return null;
    }
}
